#include "Task.hpp"

class Channel
{
public:
    Channel(int wfd, pid_t subprocess, const std::string& name)
        :_wfd(wfd),_subprocess(subprocess),_name(name)
    {}
    
    void CloseChannel()
    {
        close(_wfd);
    }

    void Wait()
    {
        int rid = waitpid(_subprocess, nullptr, 0);
        if(rid > 0)
        {
            std::cout << "wait subprocess: " << rid << "sucess" << std::endl;
        }
    }

    ~Channel()
    {}

    int Getfd() {return _wfd;}
    pid_t GetPid() { return _subprocess;}
    std::string GetName() { return _name;}

private:
    int _wfd;
    pid_t _subprocess;
    std::string _name;
};

void CreateProcessPool(int n ,std::vector<Channel> &ProcessPool)
{
    for(int i = 0; i < n; i++)
    {
        //创建管道
        int pipefd[2];
        int flag = pipe(pipefd);
        if(flag != 0)
        {
            std::cerr << "pipe failed, errno: " << errno << std::endl;
            exit(1);
        }

        //创建进程
        pid_t rid = fork();
        if(rid == 0)    //子进程
        {
            if(!ProcessPool.empty())
            {
                //std::cout << "fix bug" << std::endl;
                for(auto& e : ProcessPool)  //子进程要把所有从父进程那里继承来的以写方式打开的文件fd给关闭掉
                    e.CloseChannel();
            }
            close(pipefd[1]);
            dup2(pipefd[0], 0);
            work();

            exit(0);
        }

        close(pipefd[0]);

        std::string name = "Channel." + std::to_string(i);
        ProcessPool.push_back(Channel(pipefd[1], rid, name));
    }

}

void CtrlProcessOnce(std::vector<Channel>& ProcessPool)
{ 
    int tasknum = Select();     //选择任务
    int channel_index = SelectChannel(ProcessPool.size());     //选择管道
    
    write(ProcessPool[channel_index].Getfd(), &tasknum , sizeof(tasknum));  //发送任务
    sleep(1);
}

void CtrlProcess(std::vector<Channel>& ProcessPool, int times)
{
    if(times > 0)
    {
        while (times--)
        {
            CtrlProcessOnce(ProcessPool);
        }
    }
    else
    {
        CtrlProcessOnce(ProcessPool);
    }
}

void CleanProcessPool(std::vector<Channel>& ProcessPool)
{
    for(auto& e : ProcessPool)
    {
        e.CloseChannel();
        e.Wait();
    }
}

int main(int argc, char* argv[])
{
    if(argc < 2)
    {
        std::cerr << "Usage: " << argv[0] << " processnum" << std::endl;
        return 1;
    }
    LoadTask();

    //1.先创建管道、再创建子进程，需要注意保证管道的引用计数为一，避免出现bug
    //父进程写入，子进程读取
    //命令行控制进程的个数
    std::vector<Channel> ProcessPool;
    int num = std::stoi(argv[1]);
    CreateProcessPool(num , ProcessPool);
    
    //2.通过Channel控制子进程,使用轮询访问来使子进程负载均衡
    CtrlProcess(ProcessPool, 10);

    //3.清理开辟的管道和进程
    CleanProcessPool(ProcessPool);


    return 0;
}